package com.getan.boot.jdbc.service;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.getan.boot.common.Pagination;
import com.getan.boot.jdbc.entity.Entity;
import com.getan.boot.jdbc.repository.GenericRepository;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * Service层
 *
 * @author Bruce.Gong
 * @since 1.0.0-SNAPSHOT
 */
public interface IGenericService<E extends Entity> {

    /**
     * 默认批次提交数量
     */
    int DEFAULT_BATCH_SIZE = 1000;

    /**
     * 插入一条记录（选择字段，策略插入）
     *
     * @param entity 实体对象
     * @return true | false
     */
    @Transactional(rollbackFor = Exception.class)
    default boolean insert(E entity) {
        return SqlHelper.retBool(getGenericRepository().insert(entity));
    }

    /**
     * 插入（批量）
     *
     * @param entityList 实体对象集合
     * @return true | false
     */
    @Transactional(rollbackFor = Exception.class)
    default boolean insertBatch(Collection<E> entityList) {
        return insertBatch(entityList, DEFAULT_BATCH_SIZE);
    }

    /**
     * 插入（批量）
     *
     * @param entityList 实体对象集合
     * @param batchSize  插入批次数量
     * @return true | false
     */
    @Transactional(rollbackFor = Exception.class)
    boolean insertBatch(Collection<E> entityList, int batchSize);

    /**
     * 根据 ID 选择修改
     *
     * @param entity 实体对象
     * @return 有一条执行成功，返回 true，否则返回 false
     */
    @Transactional(rollbackFor = Exception.class)
    default boolean update(E entity) {
        return SqlHelper.retBool(getGenericRepository().updateById(entity));
    }

    /**
     * 根据ID 批量更新
     *
     * @param entityList 实体对象集合
     * @return 语句全部执行则返回 true，如果出现异常则返回 false
     */
    @Transactional(rollbackFor = Exception.class)
    default boolean updateBatch(Collection<E> entityList) {
        return updateBatch(entityList, DEFAULT_BATCH_SIZE);
    }

    /**
     * 根据ID 批量更新
     *
     * @param entityList 实体对象集合
     * @param batchSize  更新批次数量
     * @return 语句全部执行则返回 true，如果出现异常则返回 false
     */
    @Transactional(rollbackFor = Exception.class)
    boolean updateBatch(Collection<E> entityList, int batchSize);

    /**
     * 根据 UpdateWrapper 条件，更新记录 需要设置sqlset
     *
     * @param updateWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper}
     * @return 有一条执行成功，返回 true，否则返回 false
     */
    @Transactional(rollbackFor = Exception.class)
    default boolean update(Wrapper<E> updateWrapper) {
        TableInfo tableInfo = TableInfoHelper.getTableInfo(currentEntityClass());
        E instance = tableInfo.newInstance();
        return update(instance, updateWrapper);
    }

    /**
     * 根据 whereEntity 条件，更新记录
     *
     * @param entity        实体对象
     * @param updateWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper}
     * @return 有一条执行成功，返回 true，否则返回 false
     */
    @Transactional(rollbackFor = Exception.class)
    boolean update(E entity, Wrapper<E> updateWrapper);

    /**
     * 根据 ID 删除
     *
     * @param id 主键ID
     * @return 是否删除成功
     */
    @Transactional(rollbackFor = Exception.class)
    boolean delete(Serializable id);

    /**
     * 批量删除(jdbc批量提交)
     *
     * @param ids 主键ID
     * @return 删除是否成功
     */
    @Transactional(rollbackFor = Exception.class)
    default boolean deleteBatch(Collection<? extends Serializable> ids) {
        return deleteBatch(ids, DEFAULT_BATCH_SIZE);
    }


    /**
     * 批量删除(jdbc批量提交)
     *
     * @param ids       主键ID
     * @param batchSize 批次大小
     * @return 删除是否成功
     */
    @Transactional(rollbackFor = Exception.class)
    boolean deleteBatch(Collection<? extends Serializable> ids, int batchSize);

    /**
     * 根据 entity 条件，删除记录
     *
     * @param queryWrapper 实体包装类 {@link com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper}
     * @return 删除是否成功
     */
    boolean delete(Wrapper<E> queryWrapper);

    /**
     * 根据 ID 查询
     *
     * @param id 主键ID
     * @return entity
     */
    default E getById(Serializable id) {
        return getGenericRepository().selectById(id);
    }

    /**
     * 查询（根据ID 批量查询）
     *
     * @param idList 主键ID列表
     * @return entities
     */
    default List<E> listByIds(Collection<? extends Serializable> idList) {
        return getGenericRepository().selectBatchIds(idList);
    }

    /**
     * 根据 Wrapper，查询一条记录 <br/>
     * <p>结果集，如果是多个会抛出异常，随机取一条加上限制条件 wrapper.last("LIMIT 1")</p>
     *
     * @param queryWrapper 实体对象封装操作类 {@link QueryWrapper}
     * @return entity
     */
    default E getOne(Wrapper<E> queryWrapper) {
        return getOne(queryWrapper, true);
    }

    /**
     * 根据 Wrapper，查询一条记录
     *
     * @param queryWrapper 实体对象封装操作类 {@link QueryWrapper}
     * @param throwEx      有多个 result 是否抛出异常
     * @return entity
     */
    E getOne(Wrapper<E> queryWrapper, boolean throwEx);

    /**
     * 查询总记录数
     *
     * @return 记录条数
     * @see Wrappers#emptyWrapper()
     */
    default long count() {
        return count(Wrappers.emptyWrapper());
    }

    /**
     * 根据 Wrapper 条件，查询总记录数
     *
     * @param queryWrapper 实体对象封装操作类 {@link QueryWrapper}
     * @return 记录条数
     */
    default long count(Wrapper<E> queryWrapper) {
        return SqlHelper.retCount(getGenericRepository().selectCount(queryWrapper));
    }

    /**
     * 是否存在
     *
     * @return 是否存在
     * @see Wrappers#emptyWrapper()
     */
    default boolean exists() {
        return exists(Wrappers.emptyWrapper());
    }

    /**
     * 是否存在
     *
     * @param queryWrapper 实体对象封装操作类 {@link QueryWrapper}
     * @return 是否存在
     */
    default boolean exists(Wrapper<E> queryWrapper) {
        return getGenericRepository().exists(queryWrapper);
    }

    /**
     * 查询所有
     *
     * @return entities
     * @see Wrappers#emptyWrapper()
     */
    default List<E> list() {
        return list(Wrappers.emptyWrapper());
    }

    /**
     * 查询列表
     *
     * @param queryWrapper 实体对象封装操作类 {@link QueryWrapper}
     * @return entities
     */
    default List<E> list(Wrapper<E> queryWrapper) {
        return getGenericRepository().selectList(queryWrapper);
    }

    /**
     * 无条件翻页查询
     *
     * @param pagination 翻页对象
     * @return Pagination  分页对象
     * @see Wrappers#emptyWrapper()
     */
    default Pagination<E> page(Pagination<E> pagination) {
        return page(pagination, Wrappers.emptyWrapper());
    }

    /**
     * 翻页查询
     *
     * @param pagination   翻页对象
     * @param queryWrapper 实体对象封装操作类 {@link QueryWrapper}
     * @return Pagination  分页对象
     */
    default Pagination<E> page(Pagination<E> pagination, Wrapper<E> queryWrapper) {
        Page<E> page = new Page<>(pagination.getPageNum(), pagination.getPageSize());
        page = getGenericRepository().selectPage(page, queryWrapper);
        return pagination.of(page.getRecords(), page.getTotal());
    }

    /**
     * 翻页查询
     *
     * @param pageIndex    页码
     * @param pageSize     每页记录数
     * @param queryWrapper 实体对象封装操作类 {@link QueryWrapper}
     * @return Pagination  分页对象
     */
    default Pagination<E> page(Wrapper<E> queryWrapper, int pageIndex, int pageSize) {
        Pagination<E> pagination = new Pagination<>(pageIndex, pageSize);
        return page(pagination, queryWrapper);
    }

    /**
     * 根据 Wrapper，查询一条记录
     *
     * @param queryWrapper 实体对象封装操作类 {@link QueryWrapper}
     * @param mapper       转换函数
     * @return entity
     */
    <V> V getObj(Wrapper<E> queryWrapper, Function<E, V> mapper);

    /**
     * 根据 Wrapper 条件，查询全部记录
     *
     * @param queryWrapper 实体对象封装操作类 {@link QueryWrapper}
     * @param mapper       转换函数
     * @return 查询结果
     */
    default <V> List<V> listObjs(Wrapper<E> queryWrapper, Function<E, V> mapper) {
        return list(queryWrapper).stream().filter(Objects::nonNull).map(mapper).collect(Collectors.toList());
    }

    /**
     * 根据 Wrapper 条件，查询全部记录
     *
     * @param queryWrapper 实体对象封装操作类 {@link QueryWrapper}
     * @param mapper       转换函数
     * @return 查询结果
     */
    default <V> Set<V> listDistinctObjs(Wrapper<E> queryWrapper, Function<E, V> mapper) {
        return list(queryWrapper).stream().filter(Objects::nonNull).map(mapper).collect(Collectors.toSet());
    }

    /**
     * 获取对象的 Repository
     *
     * @return Repository
     */
    GenericRepository<E> getGenericRepository();

    /**
     * 获取业务对象
     *
     * @return Class
     */
    Class<E> currentEntityClass();

}
